/*
* Copyright 2010 Cloud.com, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cloud.bridge.service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import org.apache.log4j.Logger;
import com.cloud.bridge.service.exception.FileNotExistException;
import com.cloud.bridge.service.exception.InternalErrorException;
import com.cloud.bridge.service.exception.OutOfStorageException;
import com.cloud.bridge.util.FileRangeDataSource;
import com.cloud.bridge.util.StringHelper;
/**
* @author Kelven Yang
*/
public class S3FileSystemBucketAdapter implements S3BucketAdapter {
protected final static Logger logger = Logger.getLogger(S3FileSystemBucketAdapter.class);
public S3FileSystemBucketAdapter() {
}
@Override
public void createContainer(String mountedRoot, String bucket) {
String dir = getBucketFolderDir(mountedRoot, bucket);
if(!new File(dir).mkdirs())
throw new OutOfStorageException("Unable to create " + dir + " for bucket " + bucket);
}
@Override
public void deleteContainer(String mountedRoot, String bucket) {
String dir = getBucketFolderDir(mountedRoot, bucket);
File path = new File(dir);
if(!deleteDirectory(path))
throw new OutOfStorageException("Unable to delete " + dir + " for bucket " + bucket);
}
@Override
public String getBucketFolderDir(String mountedRoot, String bucket) {
String bucketFolder = getBucketFolderName(bucket);
String dir;
String separator = ""+File.separatorChar;
if(!mountedRoot.endsWith(separator))
dir = mountedRoot + separator + bucketFolder;
else
dir = mountedRoot + bucketFolder;
return dir;
}
@Override
public String saveObject(InputStream is, String mountedRoot, String bucket, String fileName) {
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
logger.error("Unexpected exception " + e.getMessage(), e);
throw new InternalErrorException("Unable to get MD5 MessageDigest", e);
}
File file = new File(getBucketFolderDir(mountedRoot, bucket) + File.separatorChar + fileName);
try {
// -> when versioning is off we need to rewrite the file contents
file.delete();
file.createNewFile();
final FileOutputStream fos = new FileOutputStream(file);
byte[] buffer = new byte[4096];
int len = 0;
while( (len = is.read(buffer)) > 0) {
fos.write(buffer, 0, len);
md5.update(buffer, 0, len);
}
fos.close();
return StringHelper.toHexString(md5.digest());
} catch(IOException e) {
logger.error("Unexpected exception " + e.getMessage(), e);
throw new OutOfStorageException(e);
}
}
@Override
public DataHandler loadObject(String mountedRoot, String bucket, String fileName) {
File file = new File(getBucketFolderDir(mountedRoot, bucket) + File.separatorChar + fileName);
try {
return new DataHandler(file.toURL());
} catch (MalformedURLException e) {
throw new FileNotExistException("Unable to open underlying object file");
}
}
@Override
public void deleteObject(String mountedRoot, String bucket, String fileName) {
String filePath = new String( getBucketFolderDir(mountedRoot, bucket) + File.separatorChar + fileName );
File file = new File( filePath );
if (!file.delete()) throw new OutOfStorageException( "Unable to delete " + filePath + " for object deletion" );
}
@Override
public DataHandler loadObjectRange(String mountedRoot, String bucket, String fileName, long startPos, long endPos) {
File file = new File(getBucketFolderDir(mountedRoot, bucket) + File.separatorChar + fileName);
try {
DataSource ds = new FileRangeDataSource(file, startPos, endPos);
return new DataHandler(ds);
} catch (MalformedURLException e) {
throw new FileNotExistException("Unable to open underlying object file");
} catch(IOException e) {
throw new FileNotExistException("Unable to open underlying object file");
}
}
public static boolean deleteDirectory(File path) {
if( path.exists() ) {
File[] files = path.listFiles();
for(int i = 0; i < files.length; i++) {
if(files[i].isDirectory()) {
deleteDirectory(files[i]);
} else {
files[i].delete();
}
}
}
return path.delete();
}
private String getBucketFolderName(String bucket) {
// temporary
String name = bucket.replace(' ', '_');
name = bucket.replace('\\', '-');
name = bucket.replace('/', '-');
return name;
}
}